<template>
  <div class="rich-text-editor">
    <!-- 标签 -->
    <div v-if="label" class="editor-label">
      <span class="label-text">{{ label }}</span>
      <span v-if="required" class="required-mark">*</span>
      <el-tooltip v-if="tooltip" :content="tooltip" placement="top">
        <el-icon class="tooltip-icon"><QuestionFilled /></el-icon>
      </el-tooltip>
    </div>

    <!-- 编辑器工具栏 -->
    <div ref="toolbarRef" class="editor-toolbar">
      <!-- 基础格式 -->
      <span class="ql-formats">
        <select class="ql-header">
          <option value="1">标题1</option>
          <option value="2">标题2</option>
          <option value="3">标题3</option>
          <option value="4">标题4</option>
          <option value="5">标题5</option>
          <option value="6">标题6</option>
          <option selected>正文</option>
        </select>
        <select class="ql-font">
          <option selected>默认</option>
          <option value="serif">宋体</option>
          <option value="monospace">等宽</option>
        </select>
        <select class="ql-size">
          <option value="small">小</option>
          <option selected>正常</option>
          <option value="large">大</option>
          <option value="huge">超大</option>
        </select>
      </span>

      <!-- 文字样式 -->
      <span class="ql-formats">
        <button class="ql-bold" title="加粗"></button>
        <button class="ql-italic" title="斜体"></button>
        <button class="ql-underline" title="下划线"></button>
        <button class="ql-strike" title="删除线"></button>
      </span>

      <!-- 文字颜色 -->
      <span class="ql-formats">
        <select class="ql-color"></select>
        <select class="ql-background"></select>
      </span>

      <!-- 对齐方式 -->
      <span class="ql-formats">
        <button class="ql-align" value="" title="左对齐"></button>
        <button class="ql-align" value="center" title="居中对齐"></button>
        <button class="ql-align" value="right" title="右对齐"></button>
        <button class="ql-align" value="justify" title="两端对齐"></button>
      </span>

      <!-- 列表 -->
      <span class="ql-formats">
        <button class="ql-list" value="ordered" title="有序列表"></button>
        <button class="ql-list" value="bullet" title="无序列表"></button>
        <button class="ql-indent" value="-1" title="减少缩进"></button>
        <button class="ql-indent" value="+1" title="增加缩进"></button>
      </span>

      <!-- 引用和代码 -->
      <span class="ql-formats">
        <button class="ql-blockquote" title="引用"></button>
        <button class="ql-code-block" title="代码块"></button>
      </span>

      <!-- 链接和媒体 -->
      <span class="ql-formats">
        <button class="ql-link" title="链接"></button>
        <button class="ql-image" title="图片"></button>
        <button class="ql-video" title="视频"></button>
      </span>

      <!-- 清除格式 -->
      <span class="ql-formats">
        <button class="ql-clean" title="清除格式"></button>
      </span>
    </div>

    <!-- 编辑器主体 -->
    <div
      ref="editorRef"
      class="editor-content"
      :class="{ 'is-disabled': disabled }"
    ></div>

    <!-- 字数统计 -->
    <div v-if="showWordCount" class="editor-footer">
      <span class="word-count" :class="{ 'is-exceed': isExceed }">
        {{ currentLength }}/{{ maxLength }}
      </span>
    </div>

    <!-- 验证错误信息 -->
    <div v-if="hasError" class="error-message">
      {{ errorMessage }}
    </div>

    <!-- 帮助文本 -->
    <div v-if="helpText && !hasError" class="help-text">
      {{ helpText }}
    </div>

    <!-- 图片上传对话框 -->
    <el-dialog
      v-model="imageDialogVisible"
      title="插入图片"
      width="500px"
      append-to-body
      destroy-on-close
    >
      <el-tabs v-model="imageTabActive">
        <!-- 上传图片 -->
        <el-tab-pane label="本地上传" name="upload">
          <image-video-upload
            v-model="uploadImages"
            :action="uploadAction"
            :headers="uploadHeaders"
            accept="image/*"
            :max-size="imageMaxSize"
            :image-max-width="imageMaxWidth"
            :image-max-height="imageMaxHeight"
            :image-quality="imageQuality"
            :enable-crop="true"
            list-type="picture-card"
            @success="handleImageSuccess"
          />
        </el-tab-pane>
        <!-- 外链图片 -->
        <el-tab-pane label="图片链接" name="url">
          <el-form :model="imageForm" label-width="80px">
            <el-form-item label="图片链接" required>
              <el-input v-model="imageForm.url" placeholder="请输入图片链接" />
            </el-form-item>
            <el-form-item label="图片说明">
              <el-input v-model="imageForm.alt" placeholder="请输入图片说明" />
            </el-form-item>
          </el-form>
        </el-tab-pane>
      </el-tabs>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="imageDialogVisible = false">取消</el-button>
          <el-button
            type="primary"
            :disabled="!canInsertImage"
            @click="insertImage"
          >
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 视频插入对话框 -->
    <el-dialog
      v-model="videoDialogVisible"
      title="插入视频"
      width="500px"
      append-to-body
      destroy-on-close
    >
      <el-form :model="videoForm" label-width="80px">
        <el-form-item label="视频链接" required>
          <el-input v-model="videoForm.url" placeholder="请输入视频链接" />
          <div class="form-tip">支持 YouTube、Bilibili 等平台的视频链接</div>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="videoDialogVisible = false">取消</el-button>
          <el-button
            type="primary"
            :disabled="!videoForm.url"
            @click="insertVideo"
          >
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import {
  ref,
  computed,
  onMounted,
  onBeforeUnmount,
  nextTick,
  watch,
} from "vue";
import { QuestionFilled } from "@element-plus/icons-vue";
import Quill from "quill";
import "quill/dist/quill.snow.css";
import ImageVideoUpload from "./ImageVideoUpload.vue";

const props = defineProps({
  modelValue: {
    type: String,
    default: "",
  },
  label: {
    type: String,
    default: "",
  },
  placeholder: {
    type: String,
    default: "请输入内容...",
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  readonly: {
    type: Boolean,
    default: false,
  },
  showWordCount: {
    type: Boolean,
    default: true,
  },
  maxLength: {
    type: Number,
    default: 0,
  },
  minLength: {
    type: Number,
    default: 0,
  },
  height: {
    type: String,
    default: "300px",
  },
  uploadAction: {
    type: String,
    required: true,
  },
  uploadHeaders: {
    type: Object,
    default: () => ({}),
  },
  imageMaxSize: {
    type: Number,
    default: 5,
  },
  imageMaxWidth: {
    type: Number,
    default: 1920,
  },
  imageMaxHeight: {
    type: Number,
    default: 1080,
  },
  imageQuality: {
    type: Number,
    default: 0.8,
  },
  required: {
    type: Boolean,
    default: false,
  },
  tooltip: {
    type: String,
    default: "",
  },
  helpText: {
    type: String,
    default: "",
  },
  rules: {
    type: Array,
    default: () => [],
  },
});

const emit = defineEmits([
  "update:modelValue",
  "change",
  "blur",
  "focus",
  "ready",
  "error",
]);

const toolbarRef = ref(null);
const editorRef = ref(null);
let quill = null;
const errorMessage = ref("");
const hasError = computed(() => !!errorMessage.value);

// 图片上传相关
const imageDialogVisible = ref(false);
const imageTabActive = ref("upload");
const uploadImages = ref([]);
const imageForm = ref({
  url: "",
  alt: "",
});
const canInsertImage = computed(() => {
  return imageTabActive.value === "upload"
    ? uploadImages.value.length > 0
    : !!imageForm.value.url;
});

// 视频插入相关
const videoDialogVisible = ref(false);
const videoForm = ref({
  url: "",
});

// 字数统计
const currentLength = computed(() => {
  const text = quill?.getText() || "";
  return text.length - 1; // 减去末尾的换行符
});
const isExceed = computed(() => {
  return props.maxLength > 0 && currentLength.value > props.maxLength;
});

// 初始化编辑器
const initQuill = () => {
  const options = {
    theme: "snow",
    modules: {
      toolbar: toolbarRef.value,
    },
    placeholder: props.placeholder,
    readOnly: props.disabled || props.readonly,
  };

  quill = new Quill(editorRef.value, options);

  // 设置初始内容
  if (props.modelValue) {
    quill.root.innerHTML = props.modelValue;
  }

  // 监听内容变化
  quill.on("text-change", () => {
    const html = quill.root.innerHTML;
    emit("update:modelValue", html);
    emit("change", html);
    validate();
  });

  // 监听焦点变化
  quill.on("selection-change", (range) => {
    if (range) {
      emit("focus", range);
    } else {
      emit("blur");
      validate();
    }
  });

  // 自定义图片处理
  const toolbar = quill.getModule("toolbar");
  toolbar.addHandler("image", () => {
    imageDialogVisible.value = true;
  });
  toolbar.addHandler("video", () => {
    videoDialogVisible.value = true;
  });

  emit("ready", quill);
};

// 验证内容
const validate = () => {
  if (!props.rules.length) return true;

  const value = quill?.root.innerHTML || "";
  const text = quill?.getText() || "";
  const length = text.length - 1;

  for (const rule of props.rules) {
    if (rule.required && !value.trim()) {
      errorMessage.value = rule.message || "请输入内容";
      return false;
    }

    if (props.maxLength > 0 && length > props.maxLength) {
      errorMessage.value = `内容长度不能超过 ${props.maxLength} 个字符`;
      return false;
    }

    if (props.minLength > 0 && length < props.minLength) {
      errorMessage.value = `内容长度不能少于 ${props.minLength} 个字符`;
      return false;
    }

    if (rule.validator) {
      try {
        const result = rule.validator(value);
        if (result !== true) {
          errorMessage.value = result || "验证失败";
          return false;
        }
      } catch (error) {
        errorMessage.value = error.message || "验证失败";
        return false;
      }
    }
  }

  errorMessage.value = "";
  return true;
};

// 处理图片上传成功
const handleImageSuccess = (response) => {
  const url = response.url; // 根据实际响应结构调整
  insertImage(url);
};

// 插入图片
const insertImage = () => {
  const quillInstance = quill;
  if (!quillInstance) return;

  const url =
    imageTabActive.value === "upload"
      ? uploadImages.value[0].url
      : imageForm.value.url;
  const alt = imageForm.value.alt;

  const range = quillInstance.getSelection(true);
  quillInstance.insertEmbed(range.index, "image", url);
  if (alt) {
    const img = quillInstance.root.querySelector(`img[src="${url}"]`);
    if (img) {
      img.alt = alt;
    }
  }
  quillInstance.setSelection(range.index + 1);

  // 重置表单
  imageDialogVisible.value = false;
  imageTabActive.value = "upload";
  uploadImages.value = [];
  imageForm.value = { url: "", alt: "" };
};

// 插入视频
const insertVideo = () => {
  const quillInstance = quill;
  if (!quillInstance) return;

  const url = videoForm.value.url;
  const range = quillInstance.getSelection(true);
  quillInstance.insertEmbed(range.index, "video", url);
  quillInstance.setSelection(range.index + 1);

  // 重置表单
  videoDialogVisible.value = false;
  videoForm.value = { url: "" };
};

// 组件挂载
onMounted(() => {
  initQuill();
});

// 监听 modelValue 变化
watch(
  () => props.modelValue,
  (newValue) => {
    if (quill && newValue !== quill.root.innerHTML) {
      quill.root.innerHTML = newValue;
    }
  },
);

// 组件卸载
onBeforeUnmount(() => {
  quill = null;
});
</script>

<style lang="scss">
.rich-text-editor {
  @apply mb-4;

  .editor-label {
    @apply flex items-center mb-1;

    .label-text {
      @apply text-sm text-gray-700 font-medium;
    }

    .required-mark {
      @apply text-red-500 ml-1;
    }

    .tooltip-icon {
      @apply ml-1 text-gray-400 cursor-help;
    }
  }

  .editor-toolbar {
    @apply border border-gray-300 rounded-t-lg bg-white;

    .ql-formats {
      @apply mr-2;
    }
  }

  .editor-content {
    @apply border border-t-0 border-gray-300 rounded-b-lg bg-white;
    height: v-bind(height);

    &.is-disabled {
      @apply bg-gray-100 cursor-not-allowed;
    }

    .ql-editor {
      @apply h-full;

      &.ql-blank::before {
        @apply text-gray-400;
      }
    }
  }

  .editor-footer {
    @apply mt-1 text-right;

    .word-count {
      @apply text-sm text-gray-500;

      &.is-exceed {
        @apply text-red-500;
      }
    }
  }

  .error-message {
    @apply mt-1 text-sm text-red-500;
  }

  .help-text {
    @apply mt-1 text-sm text-gray-500;
  }
}

// Quill 编辑器主题定制
.ql-snow {
  .ql-toolbar {
    @apply p-2;
  }

  .ql-container {
    @apply font-sans;
  }

  .ql-editor {
    @apply p-4;

    h1 {
      @apply text-3xl font-bold mb-4;
    }
    h2 {
      @apply text-2xl font-bold mb-3;
    }
    h3 {
      @apply text-xl font-bold mb-3;
    }
    h4 {
      @apply text-lg font-bold mb-2;
    }
    h5 {
      @apply text-base font-bold mb-2;
    }
    h6 {
      @apply text-sm font-bold mb-2;
    }

    p {
      @apply mb-4;
    }

    ol,
    ul {
      @apply pl-6 mb-4;
    }

    li {
      @apply mb-1;
    }

    blockquote {
      @apply border-l-4 border-gray-300 pl-4 py-1 my-4 text-gray-600;
    }

    pre {
      @apply bg-gray-100 p-4 rounded-lg my-4 font-mono text-sm;
    }

    code {
      @apply bg-gray-100 px-1 rounded font-mono text-sm;
    }

    img {
      @apply max-w-full rounded-lg;
    }

    .ql-video {
      @apply w-full aspect-video rounded-lg;
    }
  }
}

// 对话框样式
.form-tip {
  @apply mt-1 text-sm text-gray-500;
}

.dialog-footer {
  @apply flex justify-end gap-2;
}
</style>
